;;; Copyright 2010 Alessio Stalla.
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;;      http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

(in-package :dynaspring-test)

(defvar *depth* 0)
(defvar *max-depth* 2)

(defun generate-sample-bean-definition (class)
  (let ((class (jclass class)))
    `(bean ,class :scope "prototype"
           :properties ,(generate-sample-property-values
                         class (get-class-writable-properties class)))))

(defun get-class-writable-properties (class)
  (let* ((bean-info (jstatic "getBeanInfo" "java.beans.Introspector" class))
         (pds (jcall "getPropertyDescriptors" bean-info)))
    (loop
       :for pd :across pds
       :when (jcall "getWriteMethod" pd)
       :collect pd)))

(defun generate-sample-property-values (class property-descriptors)
  (loop
     :for pd :in property-descriptors
     :collect (jcall "getName" pd)
     :collect (generate-sample-value
               class
               (jcall "getPropertyType" (jcoerce pd "java.beans.PropertyDescriptor")))))

(defun generate-sample-value (class property-class)
  (cond
    ((jclass-interface-p property-class) null) ;;TODO maybe instantiate collections? Empty?
    ((jequal property-class (jclass "java.lang.String"))
     (expr (generate-random-string)))
    ((or (jequal property-class (jclass "java.lang.Integer"))
         (jequal property-class (jfield "java.lang.Integer" "TYPE")))
     (expr (generate-random-int)))
    ((or (jequal property-class (jclass "java.lang.Long"))
         (jequal property-class (jfield "java.lang.Long" "TYPE")))
     (expr (generate-random-long)))
    ((>= *depth* *max-depth*) null)
    (t (let ((*depth* (1+ *depth*)))
         (generate-sample-bean-definition property-class)))))

(defvar *random-generator* (jnew "java.util.Random"))

(defun generate-random-int ()
  (jcall "nextInt" *random-generator*))

(defun generate-random-long ()
  (jcall "nextLong" *random-generator*))

(defvar *alphabet* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!\"$%&€/()=?!;.:-_*+[]{}'|<>")
(defvar *random-string-max-length* 255)
(defvar *random-string-min-length* 0)

(defun generate-random-string
    (&key (alphabet *alphabet*) (max-length *random-string-max-length*)
     (min-length *random-string-min-length*))
  (when (> min-length max-length)
    (error "min-length = ~A is greater than max-length = ~A"
           min-length max-length))
  (let* ((length (+ min-length (random (- max-length min-length))))
         (string (make-string length))
         (alphabet-chars (length alphabet)))
    (dotimes (i length)
      (setf (aref string i) (aref alphabet (random alphabet-chars))))
    string))